/*
 * Copyright (C) 2019-2020 Alibaba Group Holding Limited
 */
#include "genie_sal.h"
#include "genie_mesh_api.h"

#include "sensor_led.h"
#include "sensor_battery.h"
#include "sensor_input.h"
#include "sensor_queue.h"
#include "sensor_factory.h"

#include "sensor.h"

static aos_timer_t enter_standby_timer;
static aos_timer_t enter_sleep_timer;
static aos_timer_t twenty_four_hours_timer;
static aos_timer_t iv_update_timer;
static aos_timer_t ota_timeout_timer;

static unsigned char delay_sleep_flag = 0;
static uint32_t boot_reason = 0;
static uint16_t passed_days = 0;
static uint16_t low_battery_report_day = 0xFFFF;
static bool is_mesh_ready = false;
static bool is_user_trigger_ota = false;

/* element configuration start */
static sig_model_element_state_t sensor_elem_state[ELEMENT_NUM];
static sig_model_powerup_t sensor_powerup[ELEMENT_NUM];

static struct bt_mesh_model primary_element[] = {
    MESH_MODEL_CFG_SRV_NULL(),
    MESH_MODEL_HEALTH_SRV_NULL(),

    MESH_MODEL_GEN_ONOFF_SRV(&sensor_elem_state[0]),
};

static struct bt_mesh_model primary_vendor_element[] = {
    MESH_MODEL_VENDOR_SRV(&sensor_elem_state[0]),
};

static struct bt_mesh_model second_element[] = {
    MESH_MODEL_GEN_ONOFF_SRV(&sensor_elem_state[1]),
};

static struct bt_mesh_model second_vendor_element[] = {
    MESH_MODEL_VENDOR_SRV(&sensor_elem_state[1]),
};

struct bt_mesh_elem sensor_elem[] = {
    BT_MESH_ELEM(0, primary_element, primary_vendor_element, GENIE_ADDR_BUTTON),
    BT_MESH_ELEM(1, second_element, second_vendor_element, GENIE_ADDR_BUTTON),
};
/* element configuration end */

#ifdef CONFIG_GENIE_OTA
bool genie_sal_ota_is_allow_reboot(void)
{
    GENIE_LOG_INFO("NOt allow to reboot!");
    if (is_user_trigger_ota == true)
    {
        is_user_trigger_ota = false;
        return true;
    }
    else
    {
        return false;
    }
}
#endif

static int check_battery_level(void);

uint32_t sensor_get_boot_reason(void)
{
    return boot_reason;
}

static void enter_sleep_mode(int check_delay)
{
    if (sensor_factory_is_factory_mode())
    {
        GENIE_LOG_INFO("fac mode no sleep");
        return;
    }

    aos_timer_stop(&enter_sleep_timer);
    aos_timer_change(&enter_sleep_timer, check_delay);
    aos_timer_start(&enter_sleep_timer);
}

static void enter_standby_timer_cb(void *timer, void *arg)
{
    if (sensor_factory_is_factory_mode())
    {
        GENIE_LOG_INFO("fac mode no standby");
        return;
    }

    if (!bt_mesh_is_provisioned() && BOOT_REASON_TYPE_GET(boot_reason) != BOOT_REASON_PROVISION)
    {
        sensor_led_do_work(LED_WORK_MODE_PROVISIONED);
        aos_msleep(2000);
        GENIE_LOG_INFO("standby due to bootup prov timeout");
        genie_lpm_set_bootup_reason(BOOT_REASON_TYPE_SET(BOOT_REASON_STANDBY));
        genie_lpm_deep_sleep();
    }
    else
    {
        //Enter sleep mode
        enter_sleep_mode(ENTER_SLEEP_QUICK_CHECK_TIMEOUT);
        bt_mesh_gatt_user_disable();
    }
}

static void enter_sleep_timer_cb(void *timer, void *arg)
{
    if (delay_sleep_flag == 1)
    {
        //GENIE_LOG_INFO("delay sleep");
        return;
    }

    if (is_mesh_ready == false)
    {
        return;
    }

    if (genie_lpm_enable(true) < 0)
    {
        //Enter low power failed,so start timer again
        enter_sleep_mode(ENTER_SLEEP_QUICK_CHECK_TIMEOUT);
    }
    else
    {
        aos_timer_stop(&enter_sleep_timer);
    }
}

static int sensor_report_cb(void *p_params, transport_result_e result_e)
{
    queue_mesg_t mesg;
    genie_transport_model_param_t *p_transport_model_param = NULL;

    memset(&mesg, 0, sizeof(queue_mesg_t));
    p_transport_model_param = (genie_transport_model_param_t *)p_params;
    mesg.type = QUEUE_MESG_TYPE_POWER;
    mesg.data = POWER_ENTER_QUICK_SLEEP_FLAG;
    if (p_transport_model_param)
    {
        mesg.element_id = bt_mesh_elem_find_id(p_transport_model_param->p_elem);
    }

    queue_send_data(&mesg);

    return 0;
}

static int report_battery_level(void)
{
    uint8_t payload[4];
    uint16_t report_battery_level = 0;
    uint32_t battery_level = 0;
    genie_transport_payload_param_t transport_payload_param;

    sensor_get_battery_level(&battery_level);
    if (battery_level == 0)
    {
        GENIE_LOG_WARN("get battery level fail");
        return -1;
    }

    report_battery_level = battery_level / 10; //Unit 0.01V
    payload[0] = ATTR_TYPE_VOLTAGE_LEVEL & 0xFF;
    payload[1] = (ATTR_TYPE_VOLTAGE_LEVEL >> 8) & 0xFF;
    payload[2] = report_battery_level & 0xFF;
    payload[3] = (report_battery_level >> 8) & 0xFF;

    memset(&transport_payload_param, 0, sizeof(genie_transport_payload_param_t));
    transport_payload_param.opid = VENDOR_OP_ATTR_INDICATE;
    transport_payload_param.p_payload = payload;
    transport_payload_param.payload_len = sizeof(payload);
    transport_payload_param.retry_cnt = EVENT_REPORT_RETRY;
    transport_payload_param.result_cb = sensor_report_cb;

    return genie_transport_send_payload(&transport_payload_param);
}

static void twenty_four_hours_timer_cb(void *timer, void *arg)
{
    passed_days++;
    if (passed_days % 2 == 0)
    {
        //wake up 15S maybe need IV update
        GENIE_LOG_INFO("iv update start,wake up");
        delay_sleep_flag = 1;
        genie_lpm_disable();
        aos_timer_stop(&iv_update_timer);
        aos_timer_start(&iv_update_timer);

        report_battery_level();
        check_battery_level();
    }
}

static void iv_update_timer_cb(void *timer, void *arg)
{
    GENIE_LOG_INFO("iv update done,goto sleep");
    delay_sleep_flag = 0;
    enter_sleep_mode(ENTER_SLEEP_QUICK_CHECK_TIMEOUT);
}

static void ota_timeout_timer_cb(void *timer, void *arg)
{
    GENIE_LOG_INFO("ota timeout dis gatt");
    bt_mesh_gatt_user_disable();
    aos_timer_stop(&ota_timeout_timer);
}

void sensor_elem_state_init(void)
{
    uint8_t index = 0;
    genie_storage_status_e ret;

    memset(sensor_elem_state, 0, sizeof(sensor_elem_state));

    // load light param
    ret = genie_storage_read_userdata(GFI_MESH_POWERUP, (uint8_t *)sensor_powerup, sizeof(sensor_powerup));
    for (index = 0; index < ELEMENT_NUM; index++)
    {
        sensor_elem_state[index].element_id = index;

        if (ret == GENIE_STORAGE_SUCCESS) //Use saved data
        {
            memcpy(&sensor_elem_state[index].powerup, &sensor_powerup[index], sizeof(sig_model_powerup_t));
        }
        else //Use default value
        {
#ifdef CONFIG_MESH_MODEL_GEN_ONOFF_SRV
            sensor_elem_state[index].powerup.last_onoff = GEN_ONOFF_DEFAULT;
#endif
        }

#ifdef CONFIG_MESH_MODEL_GEN_ONOFF_SRV
        sensor_elem_state[index].state.onoff[TYPE_PRESENT] = 0;
        sensor_elem_state[index].state.onoff[TYPE_TARGET] = sensor_elem_state[index].powerup.last_onoff;
#endif
    }
}

static void sensor_param_reset(void)
{
    genie_storage_delete_userdata(GFI_MESH_POWERUP);
}

static void sensor_save_state(sig_model_element_state_t *p_elem)
{
    uint8_t *p_read = NULL;

#ifdef CONFIG_MESH_MODEL_GEN_ONOFF_SRV
    p_elem->powerup.last_onoff = p_elem->state.onoff[TYPE_PRESENT];
    sensor_powerup[p_elem->element_id].last_onoff = p_elem->state.onoff[TYPE_PRESENT];
#endif

    p_read = aos_malloc(sizeof(sensor_powerup));
    if (!p_read)
    {
        GENIE_LOG_WARN("no mem");
        return;
    }

    genie_storage_read_userdata(GFI_MESH_POWERUP, p_read, sizeof(sensor_powerup));

    if (memcmp(sensor_powerup, p_read, sizeof(sensor_powerup)))
    {
#ifdef CONFIG_MESH_MODEL_GEN_ONOFF_SRV
        GENIE_LOG_INFO("save %d %d %d", sensor_powerup[0].last_onoff);
#endif
        genie_storage_write_userdata(GFI_MESH_POWERUP, (uint8_t *)sensor_powerup, sizeof(sensor_powerup));
    }

    aos_free(p_read);
}

static void sensor_update(sig_model_element_state_t *p_elem)
{
#ifdef CONFIG_MESH_MODEL_GEN_ONOFF_SRV
    GENIE_LOG_INFO("Onoff:%d", p_elem->state.onoff[TYPE_TARGET]);
#endif
}

static void sensor_report_poweron_state(int elem_index)
{
    uint16_t index = 0;
    uint8_t payload[10];
    genie_transport_model_param_t genie_transport_model_param;

#ifdef CONFIG_MESH_MODEL_GEN_ONOFF_SRV
    payload[index++] = ATTR_TYPE_GENERIC_ONOFF & 0xff;
    payload[index++] = (ATTR_TYPE_GENERIC_ONOFF >> 8) & 0xff;
    payload[index++] = sensor_elem_state[elem_index].state.onoff[TYPE_PRESENT];
#endif

    if (index > 0)
    {
        memset(&genie_transport_model_param, 0, sizeof(genie_transport_model_param_t));
        genie_transport_model_param.opid = VENDOR_OP_ATTR_INDICATE;
        genie_transport_model_param.data = payload;
        genie_transport_model_param.len = index;
        genie_transport_model_param.p_elem = &sensor_elem[elem_index];
        genie_transport_model_param.retry_period = EVENT_REPORT_INTERVAL;
        genie_transport_model_param.retry = EVENT_REPORT_RETRY;

        genie_transport_send_model(&genie_transport_model_param);
    }
}

static void sensor_event_handler(genie_event_e event, void *p_arg)
{
    int index = 0;
    sig_model_element_state_t *p_elem_state = NULL;

    switch (event)
    {
    case GENIE_EVT_SW_RESET:
    {
        sensor_param_reset();
    }
    break;
    case GENIE_EVT_MESH_READY:
    {
        is_mesh_ready = true;
        //User can report data to cloud at here
        GENIE_LOG_INFO("User report data");
        for (index = 0; index < ELEMENT_NUM; index++)
        {
            sensor_report_poweron_state(index);
        }
    }
    break;
    case GENIE_EVT_USER_ACTION_DONE:
    {
        p_elem_state = (sig_model_element_state_t *)p_arg;
        sensor_update(p_elem_state);
        sensor_save_state(p_elem_state);
    }
    break;
    case GENIE_EVT_SDK_MESH_SILENT_START: //provision timeout
    {
        uint32_t seq = 0;
        int seq_len = sizeof(uint32_t);

        GENIE_LOG_WARN("prov timeout");

        if (genie_ota_is_updating())
        {
            GENIE_LOG_INFO("is doing ota,so wait %dS", WAITING_OTA_TIME / 1000);
            aos_msleep(WAITING_OTA_TIME);
        }

        //do resum seq
        if (!aos_kv_get(SEQ_BACKUP_KEY, (void *)&seq, &seq_len))
        {
            GENIE_LOG_WARN("resume seq");
            genie_storage_write_seq(&seq, true);
            genie_lpm_set_bootup_reason(BOOT_REASON_TYPE_SET(BOOT_REASON_RESUME_PROV));
            aos_kv_del(SEQ_BACKUP_KEY);
            aos_reboot();
        }
        else
        {
            if (delay_sleep_flag == 1)
            {
                GENIE_LOG_INFO("delay sleep and dis GATT");
                return;
            }
            GENIE_LOG_INFO("no seq,then sleep and dis GATT");
            bt_mesh_gatt_user_disable(); //disable GATT
            enter_sleep_mode(ENTER_SLEEP_QUICK_CHECK_TIMEOUT);
        }
    }
    break;
    case GENIE_EVT_SDK_MESH_PROV_SUCCESS:
    {
        if (genie_ota_is_updating())
        {
            GENIE_LOG_INFO("is doing ota,so wait %dS", WAITING_OTA_TIME / 1000);
            aos_msleep(WAITING_OTA_TIME);
        }
        bt_mesh_gatt_user_disable(); //disable GATT
        sensor_led_do_work(LED_WORK_MODE_PROVISIONED);
    }
    break;
    case GENIE_EVT_SIG_MODEL_MSG:
    {
        sig_model_msg *p_msg = (sig_model_msg *)p_arg;

        if (p_msg)
        {
            GENIE_LOG_INFO("SIG mesg ElemID(%d)", p_msg->element_id);
        }
    }
    break;
    case GENIE_EVT_VENDOR_MODEL_MSG:
    {
        genie_transport_model_param_t *p_msg = (genie_transport_model_param_t *)p_arg;
        queue_mesg_t mesg;

        if (p_msg->opid == VENDOR_OP_ATTR_SET_ACK) //get UTC time
        {
            memset(&mesg, 0, sizeof(queue_mesg_t));
            mesg.type = QUEUE_MESG_TYPE_POWER;
            mesg.data = POWER_ENTER_SLOW_SLEEP_FLAG;
            queue_send_data(&mesg);
        }

        if (p_msg && p_msg->p_model && p_msg->p_model->user_data)
        {
            p_elem_state = (sig_model_element_state_t *)p_msg->p_model->user_data;
            GENIE_LOG_INFO("ElemID(%d) TID(%d)", p_elem_state->element_id, p_msg->tid);
        }
    }
    break;
#ifdef CONIFG_GENIE_MESH_USER_CMD
    case GENIE_EVT_DOWN_MSG:
    {
        genie_down_msg_t *p_msg = (genie_down_msg_t *)p_arg;
        //User handle this msg,such as send to MCU
        if (p_msg)
        {
        }
    }
    break;
#endif
    default:
    {
    }
    break;
    }
}

static void sensor_check_boot_reason(void)
{
    boot_reason = genie_lpm_get_bootup_reason();
    GENIE_LOG_INFO("boot reason:0x%08x\n", boot_reason);

    switch (BOOT_REASON_TYPE_GET(boot_reason))
    {
    case BOOT_REASON_RESET:
    {
        GENIE_LOG_INFO("reset done");
    }
    break;
    case BOOT_REASON_PROVISION:
    {
        GENIE_LOG_INFO("do prov");
        //bt_mesh_gatt_user_enable(); //Hers is bootup so no need enable
        sensor_led_do_work(LED_WORK_MODE_PROVISONING);
    }
    break;
    case BOOT_REASON_STANDBY:
    {
        uint32_t seq = 0;
        int seq_len = sizeof(uint32_t);

        GENIE_LOG_INFO("standby wakeup");

        //do resum seq
        if (!aos_kv_get(SEQ_BACKUP_KEY, (void *)&seq, &seq_len))
        {
            GENIE_LOG_WARN("resume seq");
            genie_storage_write_seq(&seq, true);
            aos_kv_del(SEQ_BACKUP_KEY);
        }
        enter_sleep_mode(ENTER_SLEEP_SLOW_CHECK_TIMEOUT);
    }
    break;
    case BOOT_REASON_REBOOT:
    {
        GENIE_LOG_INFO("normal boot");
    }
    break;
    case BOOT_REASON_RESUME_PROV:
    {
        GENIE_LOG_INFO("prov resume");
    }
    break;
    default:
    {
    }
    break;
    }

    genie_lpm_set_bootup_reason(0); //clear boot reason flag
}

static void sensor_timer_init(void)
{
    aos_timer_new(&enter_standby_timer, enter_standby_timer_cb, NULL, BOOTUP_ENTER_STANDBY_DELAY, 0);
    aos_timer_start(&enter_standby_timer);

    aos_timer_new(&enter_sleep_timer, enter_sleep_timer_cb, NULL, ENTER_SLEEP_SLOW_CHECK_TIMEOUT, 0);
    aos_timer_stop(&enter_sleep_timer);

    aos_timer_new(&twenty_four_hours_timer, twenty_four_hours_timer_cb, NULL, TWENTY_FOUR_HOURS_TIMEOUT, 1);
    aos_timer_start(&twenty_four_hours_timer);

    aos_timer_new(&iv_update_timer, iv_update_timer_cb, NULL, IV_UPDATE_TIMEOUT, 0);
    aos_timer_stop(&iv_update_timer);

    aos_timer_new(&ota_timeout_timer, ota_timeout_timer_cb, NULL, SENSOR_OTA_TIMEOUT, 0);
    aos_timer_stop(&ota_timeout_timer);
}

static void sensor_init(void)
{
    sensor_elem_state_init();
    sensor_timer_init();
    sensor_factory_init();
    queue_init();
    input_event_init();
    sensor_led_init();
    sensor_battery_init();
    sensor_check_boot_reason();
}

static void report_event_to_cloud(uint8_t element_id, uint8_t event)
{
    uint8_t payload[3];
    genie_transport_payload_param_t transport_payload_param;

    payload[0] = ATTR_TYPE_DEVICE_EVENT & 0xFF;
    payload[1] = (ATTR_TYPE_DEVICE_EVENT >> 8) & 0xFF;
    payload[2] = event;

    memset(&transport_payload_param, 0, sizeof(genie_transport_payload_param_t));
    transport_payload_param.element_id = element_id;
    transport_payload_param.opid = VENDOR_OP_ATTR_INDICATE;
    transport_payload_param.p_payload = payload;
    transport_payload_param.payload_len = sizeof(payload);
    transport_payload_param.retry_cnt = EVENT_REPORT_RETRY;
    transport_payload_param.result_cb = sensor_report_cb;

    genie_transport_send_payload(&transport_payload_param);
}

static void handle_input_event(switch_press_type_e press_type)
{
    uint32_t seq = 0;
    uint32_t boot_reason = 0;

    switch (press_type)
    {
    case SWITCH_PRESS_PROVISION:
    {
        GENIE_LOG_INFO("genie do provision");

        boot_reason = BOOT_REASON_TYPE_SET(BOOT_REASON_PROVISION);
        if (0 == genie_storage_read_seq(&seq))
        {
            if (0 != aos_kv_set(SEQ_BACKUP_KEY, (void *)&seq, sizeof(uint32_t), 0))
            {
                GENIE_LOG_ERR("seq backup fail");
            }
        }
        genie_lpm_set_bootup_reason(boot_reason);

        genie_storage_delete_seq();
        aos_reboot(); //reboot to do provision
    }
    break;
    case SWITCH_PRESS_ONCE:
    {
        sensor_led_do_work(LED_WORK_MODE_SINGLE_PRESS);
    }
    break;
    case SWITCH_PRESS_DOUBLE:
    {
        sensor_led_do_work(LED_WORK_MODE_DOUBLE_PRESS);
    }
    break;
    case SWITCH_PRESS_LONG:
    {
        sensor_led_do_work(LED_WORK_MODE_LONG_PRESS);
    }
    break;
    case SWITCH_PRESS_TRIPLE:
    {
    }
    break;
    case SWITCH_PRESS_RESET:
    {
        /*
        GENIE_LOG_INFO("genie do reset");
        genie_lpm_set_bootup_reason((BOOT_REASON_TYPE_SET(BOOT_REASON_RESET));
        genie_event(GENIE_EVT_HW_RESET_START, NULL);
        */
    }
    break;
    case SWITCH_PRESS_STANDBY:
    {
        sensor_led_do_work(LED_WORK_MODE_STANDBY);
        aos_msleep(1000);
        GENIE_LOG_INFO("genie enter standby");
        genie_lpm_set_bootup_reason(BOOT_REASON_TYPE_SET(BOOT_REASON_STANDBY));
        genie_lpm_deep_sleep();
    }
    break;
    case SWITCH_PRESS_PRESSED:
    {
#ifdef SENSOR_UNPROV_PROMPT
        if (!bt_mesh_is_provisioned())
        {
            sensor_set_led_status(LED_ON);
        }
#endif
    }
    break;
    case SWITCH_PRESS_RELEASED:
    {
#ifdef SENSOR_UNPROV_PROMPT
        if (!bt_mesh_is_provisioned())
        {
            sensor_set_led_status(LED_OFF);
        }
#endif
    }
    break;
    case SWITCH_PRESS_START_OTA:
    {
        is_user_trigger_ota = true;
        sensor_led_do_work(LED_WORK_MODE_OTA);
        bt_mesh_gatt_user_enable();
        genie_ota_report_version();
        aos_timer_start(&ota_timeout_timer);
    }
    break;
    default:
        break;
    }
}

static int check_battery_level(void)
{
    uint32_t battery_level = 0;

    sensor_get_battery_level(&battery_level);

    GENIE_LOG_INFO("battery_level:%d", battery_level);
    if (battery_level < SENSOR_BATTERY_LOW_LEVEL)
    {
        if (low_battery_report_day == 0xFFFF || low_battery_report_day != passed_days)
        {
            report_event_to_cloud(0, EL_LOW_BAT_T);
            low_battery_report_day = passed_days;
        }
        else
        {
            GENIE_LOG_INFO("only report once in 24h");
        }

        sensor_led_do_work(LED_WORK_MODE_LOW_BATTERY);
    }

    return 0;
}

int sensor_set_delay_sleep_flag(unsigned char flag)
{
    delay_sleep_flag = flag;

    return 0;
}

#ifdef CONFIG_PM_SLEEP
static void sensor_lpm_cb(genie_lpm_wakeup_reason_e reason, genie_lpm_status_e status, void *args)
{
    if (status == STATUS_WAKEUP)
    {
        if (reason == WAKEUP_BY_IO)
        {
            genie_lpm_io_status_list_t *list = (genie_lpm_io_status_list_t *)args;
            for (int i = 0; i < list->size; i++)
            {
                if (list->io_status[i].trigger_flag == true)
                {
                    input_event_start_check_timer(list->io_status[i].port);
                }
            }
        }

        enter_sleep_mode(KEEP_WAKEUP_STATUS_MAX_TIME); //For enter sleep fail or error wakeup
    }
    else
    {
        GENIE_LOG_INFO("sleep");
    }
}
#endif

int application_start(int argc, char **argv)
{
    queue_mesg_t queue_mesg;
    switch_press_type_e press_type;
    genie_service_ctx_t context;

    GENIE_LOG_INFO("BTIME:%s\n", __DATE__ ","__TIME__);

    sensor_init();

    memset(&queue_mesg, 0, sizeof(queue_mesg_t));
    memset(&context, 0, sizeof(genie_service_ctx_t));
    context.prov_timeout = MESH_PBADV_TIME;
    context.event_cb = sensor_event_handler;
    context.p_mesh_elem = sensor_elem;
    context.mesh_elem_counts = sizeof(sensor_elem) / sizeof(struct bt_mesh_elem);

#ifdef CONFIG_PM_SLEEP
    genie_lpm_wakeup_io_config_t io[] = {GENIE_WAKEUP_PIN(INPUT_EVENT_PIN_1, INPUT_PIN_POL_PIN_1),
                                         GENIE_WAKEUP_PIN(INPUT_EVENT_PIN_2, INPUT_PIN_POL_PIN_2)};

    genie_lpm_wakeup_io_t io_config = {sizeof(io) / sizeof(io[0]), io};
    context.lpm_conf.is_auto_enable = 1;
    context.lpm_conf.lpm_wakeup_io = 1;
    context.lpm_conf.lpm_wakeup_io_config = io_config;

    context.lpm_conf.genie_lpm_cb = sensor_lpm_cb;
#endif

    if (GENIE_SERVICE_SUCCESS != genie_service_init(&context))
    {
        //Maybe there is no triple info
        GENIE_LOG_INFO("Can i goto standby?");
    }

    //This function must called behind of genie_lpm_init
    //For check bootup key press
    input_event_init_ii();

    while (1)
    {
        if (queue_recv_data(&queue_mesg) < 0)
        {
            continue;
        }

        if (QUEUE_MESG_TYPE_INPUT == queue_mesg.type)
        {
            press_type = (switch_press_type_e)queue_mesg.data;
            if (press_type == SWITCH_PRESS_ONCE || press_type == SWITCH_PRESS_DOUBLE || press_type == SWITCH_PRESS_LONG)
            {
                if (bt_mesh_is_provisioned())
                {
                    handle_input_event(press_type);
                    report_event_to_cloud(queue_mesg.element_id, press_type);
                    check_battery_level();
                }
                else
                {
                    handle_input_event(press_type); //keep led on when switch pressed
                }
            }
            else
            {
                handle_input_event(press_type); //handle other press event
            }
        }
        else if (QUEUE_MESG_TYPE_POWER == queue_mesg.type)
        {
            if (POWER_ENTER_QUICK_SLEEP_FLAG == queue_mesg.data)
            {
                enter_sleep_mode(ENTER_SLEEP_QUICK_CHECK_TIMEOUT);
            }
            else if (POWER_ENTER_SLOW_SLEEP_FLAG == queue_mesg.data)
            {
                enter_sleep_mode(ENTER_SLEEP_SLOW_CHECK_TIMEOUT);
            }
        }
    }

    return 0;
}
